Java Web Token 之 java | 您所在的位置:网站首页 › jwt java代码 › Java Web Token 之 java |
文末附原文链接 -- 微信公众号首发Java JWT java-jwt 是JSON Web Token(JWT) - RFC 7519 的实现。 Installation Maven com.auth0 java-jwt 3.4.0Gradle compile 'com.auth0:java-jwt:3.4.0'Available Algorithms 这个库通过下面罗列的算法实现了JWT校验和签名: UsagePick the Algorithm 算法定义了如何验证和签名一个token(令牌)。在使用HMAC算法的情况下可以使用秘密(secret)进行实例化;在使用RSA和ECDSA算法的情况下可以使用密钥对或KeyProvider进行实例化。 当使用RSA和ECDSA算法时,只需要对JWT进行签名即可避免通过传递null值来指定公钥。当你只需要验证JWT时,可以使用私钥完成相同的操作。 Using static secrets or keys //HMAC Algorithm algorithmHS = Algorithm.HMAC256("secret"); //RSA RSAPublicKey publicKey = //Get the key instance RSAPrivateKey privateKey = //Get the key instance Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey);Using a KeyProvider 通过使用KeyProvider,你可以在运行时更改用于验证令牌(token)的签名或为RSA或ECDSA算法签署新令牌的密钥。这可以通过实现 RSAKeyProvider 或 ESDSAKeyProvider 这一方式来实现: getPublicKeyById(String kid) :该方法在token签名验证期间被调用,它会返回用来验证token的key。如果正在使用转置密钥,例如 JWK,它可以使用id获取正确的转置密钥。 getPrivateKey( ) ;它在令牌签名期间调用,它返回将用于签署JWT的密钥。 getPrivateKeyId( ) :它在令牌签名期间调用,它返回 getPrivateKey( ) 返回的key的id。此值优于 JWTCreator.Builder #withKeyId(String) 方法中设置的值。 如果你不需要设置kid值,请避免使用KeyProvider实例化算法。下面的代码展示了 RSAKeyProvider是如何工作的: final JwkStore jwkStore = new JwkStore("{JWKS_FILE_HOST}"); final RSAPrivateKey privateKey = //Get the key instance final String privateKeyId = //Create an Id for the above key RSAKeyProvider keyProvider = new RSAKeyProvider() { @Override public RSAPublicKey getPublicKeyById(String kid) { //Received 'kid' value might be null if it wasn't defined in the Token's header RSAPublicKey publicKey = jwkStore.get(kid); return (RSAPublicKey) publicKey; } @Override public RSAPrivateKey getPrivateKey() { return privateKey; } @Override public String getPrivateKeyId() { return privateKeyId; } }; Algorithm algorithm = Algorithm.RSA256(keyProvider); //Use the Algorithm to create and verify JWTs.Create and Sign a Token 首先通过调用 JWT.create( ) 来创建 JWTCreator 的实例。在使用builder定义token需要有的自定义Claims。最终通过调用传入 算法(Algorithm)实例的 sign( ) 方法获取token字符串: HS256 demotry { Algorithm algorithm = Algorithm.HMAC256("secret"); String token = JWT.create() .withIssuer("auth0") .sign(algorithm); } catch (JWTCreationException exception){ //Invalid Signing }RS256 demoRSAPublicKey publicKey = //Get the key instance RSAPrivateKey privateKey = //Get the key instance try { Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); String token = JWT.create() .withIssuer("auth0") .sign(algorithm); } catch (JWTCreationException exception){ //Invalid Signing configuration / Couldn't convert Claims. }如果Claim不能被转换为JSON或者使用的Key在签名时不可用,那么就会抛出 JWTCreationException 异常。 Verify a Token 首先要通过调用传入了 Algorithm 实例的 JWT.require( ) 方法来获得 JWTVerifier 实例。如果你需要token带有指定的Claim值,可以通过builder来定义。并且 build( ) 方法会返回 JWTVerifier 的实例,同时该方法只需要定义一次就可以用来验证不同的token。最后,调用 verifier.verify( ) 同时传入token: HS256 demoString token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; try { Algorithm algorithm = Algorithm.HMAC256("secret"); JWTVerifier verifier = JWT.require(algorithm) .withIssuer("auth0") .build(); //Reusable verifier instance DecodedJWT jwt = verifier.verify(token); } catch (JWTVerificationException exception){ //Invalid signature/claims }RS256 demoString token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; RSAPublicKey publicKey = //Get the key instance RSAPrivateKey privateKey = //Get the key instance try { Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); JWTVerifier verifier = JWT.require(algorithm) .withIssuer("auth0") .build(); //Reusable verifier instance DecodedJWT jwt = verifier.verify(token); } catch (JWTVerificationException exception){ //Invalid signature/claims }如果token携带的签名无效或者 Claim不匹配,就会抛出 JWTVerificationException 异常。 Time Validation JWT token可以包含一些用于验证它的日期相关信息: 该token是已发布的token: "iat" < TODAY该token还没有过期: "exp" > TODAY该token目前可用:"nbf" > TODAY对日期的验证是在验证token时自动执行的,如果验证不通过则会抛出 JWTVerificationException 异常。 使用 acceptLeeway( ) 方法可以定义token的有效时间窗口: JWTVerifier verifier = JWT.require(algorithm) .acceptLeeway(1) // 1 sec for nbf, iat and exp .build();你还可以给特定的日期Claim设置自定义值: JWTVerifier verifier = JWT.require(algorithm) .acceptLeeway(1) //1 sec for nbf and iat .acceptExpiresAt(5) //5 secs for exp .build();如果你要在自己的 app/lib 中测试这个行为,你需要把 Verification 实例强制转换成 BaseVerification 类型,然后该实例的 build( ) 方法才能接收一个自定义的 Clock: BaseVerification verification = (BaseVerification) JWT.require(algorithm) .acceptLeeway(1) .acceptExpiresAt(5); Clock clock = new CustomClock(); //Must implement Clock interface JWTVerifier verifier = verification.build(clock);Decode a Token String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; try { DecodedJWT jwt = JWT.decode(token); } catch (JWTDecodeException exception){ //Invalid token }如果token的格式不对,又或者 header 或 payload 的不是JSON,那么就会抛出 JWTDecodeException 异常。 Header Claims Algorithm ("alg") 返回值:当前算法名称 || null (没有在header中定义) String algorithm = jwt.getAlgorithm();Type ("typ") 返回值:当前type名称 || null (没有在header中定义) String type = jwt.getType();Content Type ("cty") 返回值:当前content type值 || null (没有在header中定义) String contentType = jwt.getContentType();Key Id ("kid") 返回值:当前key id || null (没有在header中定义) String keyId = jwt.getKeyId();Private Claims 要获取在header里的额外定义的Claims,可以调用 getHeaderClaim( ) ,并且传入 Claim 名称。该方法总是会返回一个 Claim,无论该Claim有没有值。调用 claim.isNull( ) 可以判断该 Claim中是否有值: Claim claim = jwt.getHeaderClaim("owner");使用 JWT.create( ) 创建token时,你可以通过调用 withHeader( ) 并传递 Map 对象来指定 header Claims: Map headerClaims = new HashMap(); headerClaims.put("owner", "auth0");String token = JWT.create() .withHeader(headerClaims) .sign(algorithm);The alg and typ values will always be included in the Header after the signing process.Payload Claims Issure ("iss") 返回值:当前Issuer value || null (没有在payload中定义) String issuer = jwt.getIssuer();Subject ("sub") 返回值:当前Subject value || null (没有在payload中定义) String subject = jwt.getSubject();Audience ("aud") 返回值:当前Audience value || null (没有在payload中定义) List audience = jwt.getAudience();Expiration Time ("exp") 返回值:当前Exporation time value || null (没有在payload中定义) Date expiresAt = jwt.getExpiresAt();Not Before ("nbf") 返回值:当前Not Before value || null (没有在payload中定义) Date notBefore = jwt.getNotBefore();Issued At ("iat")返回值:当前Issued At value || null (没有在payload中定义) Date issuedAt = jwt.getIssuedAt();JWT ID ("jti")返回值:当前JWT ID value || null (没有在payload中定义) String id = jwt.getId();Private Claims 要获取在token payload里的额外定义的Claims,可以调用 getClaim( ) ,并且传入 Claim 名称。该方法总是会返回一个 Claim,无论该Claim有没有值。调用 claim.isNull( ) 可以判断该 Claim中是否有值: Map claims = jwt.getClaims(); //Key is the Claim name Claim claim = claims.get("isAdmin"); 或 Claim claim = jwt.getClaim("isAdmin");当使用 JWT.create( ) 创建token的时候你可以通过 withClaim( ) 来创建自定义的Claim: String token = JWT.create() .withClaim("name", 123) .withArrayClaim("array", new Integer[]{1, 2, 3}) .sign(algorithm);当要验证之前定义的自定义Claim时,你可以通过雷同的操作来实现: JWTVerifier verifier = JWT.require(algorithm) .withClaim("name", 123) .withArrayClaim("array", 1, 2, 3) .build();DecodedJWT jwt = verifier.verify("my.jwt.token");Currently supported classes for custom JWT Claim creation and verification are: Boolean, Integer, Double, String, Date and Arrays of type String and Integer.Claim Class Claim 类是对Claim值的封装。它允许你可以获取各种类型的Claim。可用的辅助方法有: Primitives asBoolean( ):返回Boolean值 || null (如果无法转换)asInt( ):返回Integer值 || null (如果无法转换)asDouble( ):返回Double值 || null (如果无法转换)asLong( ):返回Long值 || null (如果无法转换)asString( ):返回String值 || null (如果无法转换)asDate( ):返回Date值 || null (如果无法转换) 该函数的目标值必须是一个 NumericDate (Unix Epoch/Timestamp)【注】JWT 标准中规定所有的NumericDate必须是秒数 Custom Classes and Collections 要以集合的形式获取Claim,你需要提供被转化的数据的类型: as(class):返回该类型的值。对于集合,你应该使用 asArray 和 asList 方法。asMap( ):返回MapasArray(class):返回指定class的数组。如果目标数据不是JSON数组则返回 null。asList(class):返回指定类型的List集合。如果目标数据不是JSON数组则返回 null。如果目标数据没能转换成给定的类型,则抛出 JWTDecodeException 异常。 |
CopyRight 2018-2019 实验室设备网 版权所有 |